package a;

import a.annotation.Component;
import a.annotation.Scope;
import a.util.ScanUtil;
import a.util.StringUtil;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BeanFactory {
    //单例的容器
    private static Map<String, Object> singleton = new HashMap<String, Object>();
    //原型的容器
    private static Map<String, BeanDefinition> prototype = new HashMap<String, BeanDefinition>();
    public BeanFactory(String path) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        init(path);
        initSingleton();
    }
    //初始化原型容器
    public static void init(String path) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ScanUtil s = new ScanUtil();
        List<String> scan = s.scan(path);
        for (String file : scan) {
            Class<?> clazz = Class.forName(file);
            //如果Component这个注解就交到容器里面管理
            if (clazz.isAnnotationPresent(Component.class)) {
                    BeanDefinition bean = createdefinition(clazz);
                    prototype.put(bean.getId(),bean);
                 }
             }
        }
    //初始化单例容器
    private void initSingleton() {
        for (String key : prototype.keySet()) {
            BeanDefinition beanDefinition = prototype.get(key);
            if ("singleton".equals(beanDefinition.getScope())) {
                try {
                    Object instance = createBean(beanDefinition);
                    singleton.put(key, instance);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private static BeanDefinition createdefinition(Class<?> clazz){
        BeanDefinition bean=new BeanDefinition();
        //得到Component注解的值
        String value = ComponentMethod(clazz);
        bean.setId(value);
        //判断是否有scope这个注解
        String scope = ScopeMethod(clazz);
        bean.setScope(scope);
        bean.setClassName(clazz);
        //判断是否有初始化这个注解
        Method construct = Construct(clazz);
        bean.setInit(construct);
        //判断是否有销毁这个注解
        Method destroy = Destroy(clazz);
        bean.setDestroy(destroy);
        return bean;
    }
    //获取Component这个注解的值
    private static String ComponentMethod(Class<?> clazz){
        String value = clazz.getAnnotation(Component.class).value();
        if ("".equals(value)){
            value= StringUtil.toLowerCaseFirstOne(clazz.getSimpleName());
        }
        return value;
    }
    //获取scope这个注解的值
    private static String ScopeMethod(Class<?> clazz){
        String scope=null;
        if (clazz.isAnnotationPresent(Scope.class)){
           scope = clazz.getAnnotation(Scope.class).value();
        }else {
            scope="singleton";
        }
        return scope;
    }
    //判断是否有初始化这个注解
    public static Method Construct(Class<?> clazz){
        Method mm=null;
        Method[] declaredMethods =clazz.getDeclaredMethods();
        for (Method m:declaredMethods){
            if (m.isAnnotationPresent(PostConstruct.class)){
                mm=m;
            }
        }
        return mm;
    }
    //判断是否有销毁这个注解
    public static Method Destroy(Class<?> clazz){
        Method mm=null;
        Method[] declaredMethods =clazz.getDeclaredMethods();
        for (Method m:declaredMethods){
            if (m.isAnnotationPresent(PreDestroy.class)){
                mm=m;
            }
        }
        return mm;
    }
    //创建已经注入好实例bean
    private Object createBean(BeanDefinition beanDefinition){
        Object instance = null;
        try {
            Class<?> clazz = beanDefinition.getClassName();
            instance = clazz.newInstance();
            //执行实例初始化的方法
            executeInit(instance,beanDefinition);
            //给这个clazz对象进行注入
            InjectMethod.execute(instance, clazz, this);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return instance;
    }
    public Object getBean(String name){
        return doGetBean(name);
    }
    public <T> T getBean(String name, Class<T> clazz) {
        return (T) doGetBean(name);
    }
    public Object doGetBean(String name) {
        //String scope = prototype.get(name).getScope();
        Object bean = singleton.get(name);
        if (bean == null) {
            bean = createBean(prototype.get(name));
        }
        return bean;
    }
    //执行销毁的方法
    public void executeDestroy(){
        for (String key:prototype.keySet()){
            BeanDefinition bean=prototype.get(key);
            if("singleton".equals(bean.getScope())){
                Object o = singleton.get(bean.getId());
                try {
                    if (bean.getDestroy()!=null) {
                        bean.getDestroy().invoke(o) ;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //执行初始化的方法
    public void executeInit(Object o,BeanDefinition definition){
        Method destroy = definition.getInit();
        try {
            if (destroy!=null) {
                destroy.invoke(o);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    public void close(){
        executeDestroy();
        singleton.clear();
        prototype.clear();
    }
}
